package com.own.component.store.local.method;

import com.own.component.store.core.method.StoreList;
import com.own.component.store.core.property.LocalStoreProperty;
import com.own.component.store.local.method.scheduler.StoreListScheduler;
import com.own.component.store.local.method.state.StoreState;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * DefaultLocalStoreList
 *
 * @author chenxueli
 * @date 2022-06-15 03:14:15
 */
@Slf4j
public class DefaultLocalStoreList<T> extends DefaultBaseStoreMethod<List<T>> implements StoreList<T> {

    private final ReentrantReadWriteLock cacheLock = new ReentrantReadWriteLock(true);
    private final Lock writeLock = cacheLock.writeLock();
    private final Lock readLock = cacheLock.readLock();

    public DefaultLocalStoreList() {
        super(new StoreState<>());
    }

    public DefaultLocalStoreList(long delay) {
        super(new StoreState<>(), StoreListScheduler.INSTANCE, delay);
    }

    public DefaultLocalStoreList(LocalStoreProperty properties) {
        super(new StoreState<>(), StoreListScheduler.INSTANCE, properties);
    }

    /**
     * 获取缓存的长度
     *
     * @param name 唯一key
     * @return 长度
     */
    @Override
    public Long size(String name) {
        readLock.lock();
        try {
            return (long) getStoreState().get(buildKey(name)).size();
        } finally {
            readLock.unlock();
        }
    }

    /**
     * 获取所有的key
     *
     * @return 所有的key
     */
    @Override
    public Set<String> keySet() {
        readLock.lock();
        try {
            return getStoreState().keySet();
        } finally {
            readLock.unlock();
        }
    }

    /**
     * 获取整个列表
     *
     * @param name 唯一key
     * @return 列表
     */
    @Override
    public List<T> get(String name) {
        readLock.lock();
        try {
            return getStoreState().get(buildKey(name));
        } finally {
            readLock.unlock();
        }
    }

    /**
     * 获取子集
     *
     * @param name  唯一key
     * @param start 开始位置
     * @param end   结束位置
     * @return 列表
     */
    @Override
    public List<T> range(String name, long start, long end) {
        readLock.lock();
        try {
            List<T> list = getStoreState().get(buildKey(name));
            return list.subList((int) start, (int) end);
        } finally {
            readLock.unlock();
        }
    }

    /**
     * 根据索引获取值
     *
     * @param name  唯一key
     * @param index 索引
     * @return 值
     */
    @Override
    public T index(String name, long index) {
        readLock.lock();
        try {
            return get(name).get((int) index);
        } finally {
            readLock.unlock();
        }
    }

    /**
     * 获取最左侧的值
     *
     * @param name 唯一key
     * @return 值
     */
    @Override
    public T leftPop(String name) {
        readLock.lock();
        try {
            return get(name).get(0);
        } finally {
            readLock.unlock();
        }
    }

    /**
     * 获取最右侧的值
     *
     * @param name 唯一key
     * @return 值
     */
    @Override
    public T rightPop(String name) {
        readLock.lock();
        try {
            return get(name).get((int) (size(name) - 1));
        } finally {
            readLock.unlock();
        }
    }

    /**
     * 设置值
     *
     * @param name  唯一key
     * @param index 位置
     * @param value 值
     */
    @Override
    public void set(String name, int index, T value) {
        writeLock.lock();
        try {
            if (!contains(name)) {
                getStoreState().set(buildKey(name), new ArrayList<>());
            }
            getStoreState().get(buildKey(name)).add(index, value);
        } finally {
            writeLock.unlock();
        }
    }

    /**
     * 插入值
     *
     * @param name  唯一key
     * @param value 值
     */
    @Override
    public void add(String name, T value) {
        writeLock.lock();
        try {
            if (!contains(name)) {
                getStoreState().set(buildKey(name), new ArrayList<>());
            }
            getStoreState().get(buildKey(name)).add(value);
        } finally {
            writeLock.unlock();
        }
    }

    /**
     * 插入值
     *
     * @param name   唯一key
     * @param values 值列表
     */
    @Override
    public void add(String name, T... values) {
        writeLock.lock();
        try {
            if (!contains(name)) {
                getStoreState().set(buildKey(name), new ArrayList<>());
            }
            getStoreState().get(buildKey(name)).addAll(Arrays.asList(values));
        } finally {
            writeLock.unlock();
        }
    }

    /**
     * 右侧插入值
     *
     * @param name  唯一key
     * @param value 值
     */
    @Override
    public void rightAdd(String name, T value) {
        writeLock.lock();
        try {
            if (!contains(name)) {
                getStoreState().set(buildKey(name), new ArrayList<>());
            }
            getStoreState().get(buildKey(name)).add((int) (size(name) - 1), value);
        } finally {
            writeLock.unlock();
        }
    }

    /**
     * 右侧插入值
     *
     * @param name   唯一key
     * @param values 值列表
     */
    @Override
    public void rightAdd(String name, T... values) {
        writeLock.lock();
        try {
            if (!contains(name)) {
                getStoreState().set(buildKey(name), new ArrayList<>());
            }
            getStoreState().get(buildKey(name)).addAll((int) (size(name) - 1), Arrays.asList(values));
        } finally {
            writeLock.unlock();
        }
    }

    /**
     * 是否包含
     *
     * @param name  唯一key
     * @param value 值
     * @return 是否包含
     */
    @Override
    public boolean contains(String name, T value) {
        readLock.lock();
        try {
            if (contains(name)) {
                return getStoreState().get(buildKey(name)).contains(value);
            }
            return false;
        } finally {
            readLock.unlock();
        }
    }

    /**
     * 根据索引移除
     *
     * @param name  唯一key
     * @param index 索引
     */
    @Override
    public void remove(String name, int index) {
        writeLock.lock();
        try {
            if (contains(name)) {
                getStoreState().get(buildKey(name)).remove(index);
            }
        } finally {
            writeLock.unlock();
        }
    }

    /**
     * 根据值移除左侧第一个匹配的值
     *
     * @param name  唯一key
     * @param value 值
     */
    @Override
    public void remove(String name, T value) {
        writeLock.lock();
        try {
            if (contains(name)) {
                getStoreState().get(buildKey(name)).remove(value);
            }
        } finally {
            writeLock.unlock();
        }
    }

}
